package service

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"multimedia/conf"
	"multimedia/smscode"
	"multimedia/utils"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	uuid "github.com/satori/go.uuid"
	log "github.com/sirupsen/logrus"
)

// 预定会议/快速会议
func (s *Srv) AddConferenceInfo(c *gin.Context) {
	var Confer utils.AddConferReq
	if err := c.ShouldBindBodyWith(&Confer, binding.JSON); err != nil {
		log.WithField("func", "AddConferenceInfo").Errorf(err.Error())
		c.JSON(http.StatusBadRequest, gin.H{"code": utils.ReqParamErr, "msg": ""})
		return
	}
	log.WithField("Func", "AddConferenceInfo").Infof(" the Confer is:%+v", Confer)

	// 周期性会议
	if Confer.Cycle == 1 {
		groupId := uuid.NewV4().String()
		// 添加周期会议规则
		count := s.mysql.AddCycleRule(&Confer, groupId)
		if count < 1 {
			c.JSON(http.StatusBadRequest, gin.H{"code": utils.AddFail, "msg": "周期会议规则添加异常"})
			return
		}
		// 周期会议数据
		no, firstRoomId := s.AddCycleConfe(&Confer, groupId)
		confer := s.mysql.GetConfeByRoomId(firstRoomId)
		if no < 1 {
			c.JSON(http.StatusBadRequest, gin.H{"code": utils.AddFail, "msg": "周期会议数据添加异常"})
			return
		}
		m := map[string]interface{}{
			"confeId": confer.Id,
			"roomId":  firstRoomId,
		}
		c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(m)})
		return
	}

	confeNoMakerUrl := conf.ConfigFile.ConfeNoMakerHost + utils.CONFE_NO_MAKER_URL
	res, err := s.HttpGet(confeNoMakerUrl, nil)
	if err != nil {
		log.WithField("Func", "AddConferenceInfo").Errorf("http get rpc error", err)
		c.JSON(http.StatusBadRequest, gin.H{"code": utils.ServiceInternalErr, "msg": "生成房间号失败"})
		return
	}
	var resp utils.Response
	_ = json.Unmarshal(res, &resp)
	roomId := resp.Data
	if roomId == "" {
		log.WithField("func:", "AddConferenceInfo").Errorf("room id is empty", err)
		c.JSON(http.StatusBadRequest, gin.H{"code": utils.ServiceInternalErr, "msg": "生成房间号失败"})
		return
	}
	// 快速会议
	if Confer.Type == 0 {
		now := time.Now()
		startTime := utils.FormatAsString(now, "")
		du, _ := time.ParseDuration("30m")
		endTime := utils.FormatAsString(now.Add(du), "")
		Confer.StartTime = startTime
		Confer.EndTime = endTime
		Confer.Allow = 1
		Confer.Toplimit = 50
	}
	id := s.mysql.AddConference(&Confer, roomId)
	if id < 1 {
		c.JSON(http.StatusBadRequest, gin.H{"code": utils.DBError, "msg": ""})
		return
	}
	m := map[string]interface{}{
		"confeId": id,
		"roomId":  roomId,
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(m)})
}

// 添加周期性会议
// func (s *Srv) addCycleConfe_2(Confer *utils.AddConferReq, groupId string) int64 {
// 	var buffer bytes.Buffer
// 	sql := "insert into mc_conference values "
// 	if _, err := buffer.WriteString(sql); err != nil {
// 		log.WithField("Func", "CycleConfeInsert").Errorf("sql convert buffer fail. %v", err)
// 		return 0
// 	}
// 	startTime := Confer.StartTime
// 	endTime := Confer.EndTime
// 	closeDate := Confer.CloseDate
// 	startTimeD := utils.FormatAsTime(startTime)
// 	endTimeD := utils.FormatAsTime(endTime)
// 	closeDateD := utils.FormatAsTime(closeDate)
// 	for {
// 		if endTimeD.After(closeDateD) {
// 			break
// 		}
// 		res, err := s.HttpGet(utils.CONFE_NO_MAKER_URL, nil)
// 		if err != nil {
// 			log.WithField("Func", "addCycleConfe_2").Errorf("http get rpc error", err)
// 			continue
// 		}
// 		var resp utils.Response
// 		_ = json.Unmarshal(res, &resp)
// 		roomId := resp.Data
// 		if roomId == "" {
// 			log.WithField("func:", "addCycleConfe_2").Errorf("room id is empty", err)
// 			continue
// 		}
// 		startTimeStr := utils.FormatAsString(startTimeD, "")
// 		endTimeStr := utils.FormatAsString(endTimeD, "")
// 		curTime := utils.GetCurrentTime()
// 		buffer.WriteString(fmt.Sprintf("(null,'%s','%s', %d,'%s','%s','%s','%s', %d, %d, %d, %d, null,'%s','%s', %d, %v, %d, %d),",
// 			roomId, groupId, Confer.Type, Confer.Theme, startTimeStr, endTimeStr, Confer.TimeZone, Confer.Creator,
// 			Confer.Toplimit, Confer.Allow, Confer.Cycle, curTime, curTime, 0, false, Confer.DisableAudio, Confer.Watermark))
// 		startTimeD = startTimeD.AddDate(0, 0, 1)
// 		endTimeD = endTimeD.AddDate(0, 0, 1)
// 	}
// 	sqlStr := strings.Trim(buffer.String(), ",") + ";"
// 	result := s.mysql.CycleConfeInsert(sqlStr)
// 	return result
// }

// 添加周期性会议
func (s *Srv) AddCycleConfe(Confer *utils.AddConferReq, groupId string) (int64, string) {
	st := Confer.StartTime
	cd := Confer.CloseDate
	startTime := utils.FormatAsTime(st)
	untilDate := utils.FormatAsTime(cd)
	cycleType := Confer.CycleType
	untilType := Confer.UntilType // 结束重复类型。0：结束于某天； 1：限定会议次数。
	untilCount := Confer.UntilCount
	day := 0
	switch cycleType {
	case 1: // 每周一至周五（工作日）
		day = 1
	case 2: // 每周
		day = 7
	case 3: // 每两周
		day = 14
	case 4: // 每月
		dateList := NextMonth(startTime, untilDate, untilType, untilCount)
		return s.packageSql(Confer, dateList, groupId)
	case 5: // 自定义 —— 0：天；1：周；2：按月，以星期为粒度重复；3：按月，以日期为粒度重复
		customCycleType := Confer.CustomizedCycleType
		customCycleStep := Confer.CustomizedCycleStep
		week := Confer.CustomCycleDays
		switch customCycleType {
		case 0:
			day = customCycleStep
		case 1:
			dateList := getDateByWeek(customCycleStep, untilType, untilCount, startTime, untilDate, week)
			return s.packageSql(Confer, dateList, groupId)
		case 2:
			wo := Confer.WeekOrder
			dateList := getDateByMonth(customCycleStep, untilType, untilCount, wo, startTime, untilDate, week[0])
			return s.packageSql(Confer, dateList, groupId)
		case 3:

		default:

		}
	default: // 0：每天
		day = 1
	}
	dateList := packageDateList(startTime, untilDate, cycleType, untilType, untilCount, day)
	num, firstRoomId := s.packageSql(Confer, dateList, groupId)
	return num, firstRoomId
}

// 拼装日期
func packageDateList(startTime, untilDate time.Time, cycleType, untilType, untilCount, day int) (dateList []time.Time) {
	for i := 0; i < 2400; i++ {
		if cycleType == 1 && (startTime.Weekday() == time.Sunday || startTime.Weekday() == time.Saturday) {
			startTime = startTime.AddDate(0, 0, day)
			continue
		}
		if untilType == 0 && startTime.After(untilDate) {
			break
		}
		dateList = append(dateList, startTime)
		if untilType == 1 && len(dateList) >= untilCount {
			break
		}
		startTime = startTime.AddDate(0, 0, day)
	}
	return
}

// 每月
func NextMonth(begin, untilDate time.Time, untilType, untilCount int) (dateList []time.Time) {
	dateList = append(dateList, begin)
	lastDate := begin.AddDate(0, 1, -begin.Day())
	endTime := begin
	for i := 0; i < 1550; i++ {
		if (begin.Month() != 2 && lastDate.Day() == begin.Day()) || (endTime.Month() == 1 && begin.Day() > 28) {
			endTime = begin.AddDate(0, 1+i+1, -begin.Day())
		} else {
			endTime = begin.AddDate(0, 1+i, 0)
		}
		if untilType == 0 && endTime.After(untilDate) {
			break
		}
		dateList = append(dateList, endTime)

		if untilType == 1 && len(dateList) >= untilCount {
			break
		}
	}
	return
}

// 按周拼装日期
func getDateByWeek(step, untilType, untilCount int, startTime, untilDate time.Time, week []int) (dateList []time.Time) {
	mapset := utils.ConvertIntSlice2Map(week)
	for i := 0; i < 201; i += step {
		offset := int(time.Monday - startTime.Weekday())
		//周日做特殊判断 因为time.Monday = 0
		if offset > 0 {
			offset = -6
		}
		for j := 0; j < 7; j++ {
			nextTime := startTime.AddDate(0, 0, offset+j+7*i)
			if nextTime.Before(startTime) {
				continue
			}
			if untilType == 0 && nextTime.After(untilDate) {
				break
			}
			if _, ok := mapset[int(nextTime.Weekday())]; ok {
				dateList = append(dateList, nextTime)
			}
			if untilType == 1 && len(dateList) >= untilCount {
				break
			}
		}
	}
	return
}

// 按月拼装日期
func getDateByMonth(step, untilType, untilCount, weekOrder int, startTime, untilDate time.Time, week int) (dateList []time.Time) {
	dateList = append(dateList, startTime)
	year, month, _ := startTime.Date()
	thisMonth_1 := time.Date(year, month, 1, startTime.Hour(), startTime.Minute(), startTime.Second(), 0, time.Local) // 本月1号
	for i := step; i < 201; i += step {
		times := 0
		nextMonth_1 := thisMonth_1.AddDate(0, i, 0)                             // step个月后的1号
		days := getYearMonthToDay(nextMonth_1.Year(), int(nextMonth_1.Month())) // 该月有几天
		for j := 0; j < days; j++ {
			nextDay := nextMonth_1.AddDate(0, 0, j)
			if untilType == 0 && nextDay.After(untilDate) {
				break
			}
			if int(nextDay.Weekday()) == week {
				times++
				if times == weekOrder {
					dateList = append(dateList, nextDay)
					if untilType == 1 && len(dateList) >= untilCount {
						break
					}
				}
			}
		}
	}
	return
}

// @description 查询指定年份指定月份有多少天
// @params year int 指定年份
// @params month int 指定月份
func getYearMonthToDay(year int, month int) int {
	// 有31天的月份
	day31 := map[int]struct{}{
		1:  {},
		3:  {},
		5:  {},
		7:  {},
		8:  {},
		10: {},
		12: {},
	}
	if _, ok := day31[month]; ok {
		return 31
	}
	// 有30天的月份
	day30 := map[int]struct{}{
		4:  {},
		6:  {},
		9:  {},
		11: {},
	}
	if _, ok := day30[month]; ok {
		return 30
	}
	// 计算是平年还是闰年
	if (year%4 == 0 && year%100 != 0) || year%400 == 0 {
		// 得出2月的天数
		return 29
	}
	// 得出2月的天数
	return 28
}

// 拼装sql
func (s *Srv) packageSql(Confe *utils.AddConferReq, dateSlice []time.Time, groupId string) (int64, string) {
	if len(dateSlice) <= 0 {
		return 0, ""
	}
	startTimeD := utils.FormatAsTime(Confe.StartTime)
	endTimeD := utils.FormatAsTime(Confe.EndTime)
	sub := endTimeD.Sub(startTimeD)
	var buffer bytes.Buffer
	sql := "insert into mc_conference values "
	if _, err := buffer.WriteString(sql); err != nil {
		log.WithField("Func", "packageSql").Errorf("sql convert buffer fail. %v", err)
		return 0, ""
	}
	firstRoomId := ""
	for _, ele := range dateSlice {
		confeNoMakerUrl := conf.ConfigFile.ConfeNoMakerHost + utils.CONFE_NO_MAKER_URL
		res, err := s.HttpGet(confeNoMakerUrl, nil)
		if err != nil {
			log.WithField("Func", "packageSql").Errorf("http get rpc error", err)
			continue
		}
		var resp utils.Response
		_ = json.Unmarshal(res, &resp)
		roomId := resp.Data
		if roomId == "" {
			log.WithField("func:", "packageSql").Errorf("room id is empty", err)
			continue
		}
		if firstRoomId == "" {
			firstRoomId = roomId
		}
		startTime := utils.FormatAsString(ele, "")
		etd := ele.Add(sub)
		endTime := utils.FormatAsString(etd, "")
		now := utils.GetCurrentTime()
		buffer.WriteString(fmt.Sprintf("(null,'%s','%s', %d,'%s','%s','%s','%s', %d, %d, %d, %d, null,'%s','%s', %d, %v, %d, %d, %d, %d,'%s'),",
			roomId, groupId, Confe.Type, Confe.Theme, startTime, endTime, Confe.TimeZone, Confe.Creator, Confe.Toplimit,
			Confe.Allow, Confe.Cycle, now, now, 0, false, Confe.DisableAudio, Confe.Watermark, 0, Confe.SetPassword, Confe.MeetingPassword))
	}
	sqlStr := strings.Trim(buffer.String(), ",") + ";"
	result := s.mysql.CycleConfeInsert(sqlStr)
	return result, firstRoomId
}

// 会议列表
func (s *Srv) GetConferenceList(c *gin.Context) {
	userIdStr := c.Request.Header.Get("userId")
	groupId := c.Query("groupId")
	confeListRes := make([]utils.ConfeRes, 0)
	if groupId != "" {
		s.mysql.GetCycleConfList(groupId, &confeListRes)
	} else {
		userId, _ := strconv.ParseInt(userIdStr, 10, 64)
		s.mysql.GetConfListByParam(userId, &confeListRes)
		for i := range confeListRes {
			for j, conferenceRes := range confeListRes[i].ConfeList {
				confe := s.wsClient.GetConference(conferenceRes.Id)
				if confe != nil {
					log.WithField("func:", "GetConferenceList").Infof(" the confer is id is:%d,%s",
						conferenceRes.Id, conferenceRes.RoomId)
					confeListRes[i].ConfeList[j].State = 1
				} else {
					end := utils.FormatAsTime(conferenceRes.EndTime)
					log.WithField("func:", "GetConferenceList").Infof(" the confer is nil id is:%d,%s",
						conferenceRes.Id, conferenceRes.RoomId)
					if end.Unix() < time.Now().Unix() {
						confeListRes[i].ConfeList[j].State = 2
					}
				}
			}
		}
	}
	if confeListRes == nil {
		c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": ""})
		return
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(confeListRes)})
}

// 编辑会议信息
func (s *Srv) EditConferenceInfo(c *gin.Context) {
	var confeUpdate utils.ConfeUpdate
	if er := c.ShouldBindBodyWith(&confeUpdate, binding.JSON); er != nil {
		log.WithField("Func", "EditConferenceInfo").Errorf("parameter error ! error is:%v", er)
		c.JSON(http.StatusOK, gin.H{"code": utils.ReqParamErr, "msg": "参数错误"})
	}
	log.WithField("Func", "EditConferenceInfo").Infof(" the confeUpdate is:%v", confeUpdate)
	userIdStr := c.Request.Header.Get("userId")
	newCycle := confeUpdate.Cycle
	updateId := confeUpdate.Id
	newGroupId := confeUpdate.GroupId
	confe := s.mysql.GetConferById(updateId)
	localId := confe.Id
	groupId := confe.GroupId
	cycle := confe.Cycle
	if confe.Creator != userIdStr {
		c.JSON(http.StatusOK, gin.H{"code": utils.DateNotFound, "msg": "无操作权限！"})
		return
	}
	if localId == 0 {
		c.JSON(http.StatusOK, gin.H{"code": utils.DateNotFound, "msg": ""})
		return
	}
	if newCycle == 0 && cycle == 0 {
		res := s.mysql.EditConferenceInfo(&confeUpdate)
		if !res {
			c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": "", "data": utils.EncryptDataByAes(res)})
			return
		}
	} else if newCycle == 0 && cycle == 1 {
		confeUpdate.GroupId = ""
		confeUpdate.CloseDate = ""
		s.mysql.EditConferenceInfo(&confeUpdate)
		s.mysql.DeleteCycleConfe(groupId)
		s.mysql.DeleteCloseCycleConfe(groupId)
	} else if newCycle == 1 && cycle == 0 {
		s.mysql.DeleteConferenceInfo(localId)
		creator, _ := strconv.ParseInt(confe.Creator, 10, 64)
		addConfe := s.convertConfe(confeUpdate, creator)
		groupId := uuid.NewV4().String()
		s.AddCycleConfe(&addConfe, groupId)
		s.mysql.AddCycleRule(&addConfe, groupId)
	} else if newCycle == 1 && cycle == 1 {
		if newGroupId == "" {
			confeUpdate.GroupId = groupId
			res := s.mysql.EditConferenceInfo(&confeUpdate)
			if !res {
				c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": "", "data": utils.EncryptDataByAes(res)})
				return
			}
		}
		s.mysql.DeleteCycleConfe(groupId)
		s.mysql.DeleteCloseCycleConfe(groupId)
		creator, _ := strconv.ParseInt(confe.Creator, 10, 64)
		addConfe := s.convertConfe(confeUpdate, creator)
		startTime := confeUpdate.StartTime
		startTimeD := utils.FormatAsTime(startTime)
		zeroTimeD := utils.GetZeroTimeD(time.Now())
		if zeroTimeD.After(startTimeD) {
			nowDay := utils.GetCurrentTime()
			nd := strings.Split(nowDay, " ")
			st := strings.Split(startTime, " ")
			nt := strings.Split(confeUpdate.EndTime, " ")
			addConfe.StartTime = fmt.Sprintf(nd[0], " ", st[1])
			addConfe.EndTime = fmt.Sprintf(nd[0], " ", nt[1])
		}
		s.AddCycleConfe(&addConfe, groupId)
		s.mysql.UpdateCycleRule(&confeUpdate)
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(true)})
}

func (s *Srv) convertConfe(Confer utils.ConfeUpdate, creator int64) utils.AddConferReq {
	var addConfe utils.AddConferReq
	addConfe.Type = 1
	addConfe.Theme = Confer.Theme
	addConfe.StartTime = Confer.StartTime
	addConfe.EndTime = Confer.EndTime
	addConfe.Creator = creator
	addConfe.Allow = Confer.Allow
	addConfe.Cycle = Confer.Cycle
	addConfe.CloseDate = Confer.CloseDate
	addConfe.DisableAudio = Confer.DisableAudio
	addConfe.Watermark = Confer.Watermark
	addConfe.SetPassword = Confer.SetPassword
	addConfe.MeetingPassword = Confer.MeetingPassword
	return addConfe
}

// 删除会议
func (s *Srv) DeleteConferenceInfo(c *gin.Context) {
	idStr := c.Query("id")
	id, _ := strconv.ParseInt(idStr, 10, 64)
	groupId := c.Query("groupId")
	userIdStr := c.Request.Header.Get("userId")
	confe := s.mysql.GetConferById(id)
	if confe.Creator != userIdStr {
		c.JSON(http.StatusOK, gin.H{"code": utils.DateNotFound, "msg": "无操作权限！"})
		return
	}
	log.WithField("Func", "DeleteConferenceInfo").Infof(" the idStr is:%s,the groupId is:%s", idStr, groupId)
	if (idStr == "" && groupId == "") || (idStr != "" && groupId != "") {
		c.JSON(http.StatusOK, gin.H{"code": utils.ReqParamErr, "msg": "参数有误"})
		return
	}
	if idStr != "" {
		res := s.mysql.DeleteConferenceInfo(id)
		if res < 1 {
			c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": "", "data": utils.EncryptDataByAes(false)})
			return
		}
	} else {
		res := s.deleteCycleConfe(groupId)
		if res < 1 {
			c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": "", "data": utils.EncryptDataByAes(false)})
			return
		}
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(true)})
}

// 删除周期会议
func (s *Srv) deleteCycleConfe(groupId string) int64 {
	res := s.mysql.DeleteCycleConfe(groupId)
	if res < 1 {
		return res
	}
	resu := s.mysql.DeleteCloseCycleConfe(groupId)
	if resu < 0 {
		return resu
	}
	return 1
}

// 批量删除个人参会记录
func (s *Srv) BatchDeleteIndivRecord(c *gin.Context) {
	var rPIds utils.RPIds
	err := c.BindJSON(&rPIds)
	if err != nil {
		log.WithField("Func", "BatchDeleteIndivRecord").Warnf("bind json error", err)
		c.JSON(http.StatusOK, gin.H{"code": utils.ServiceInternalErr, "msg": "", "data": utils.EncryptDataByAes(false)})
		return
	}
	log.WithField("Func", "BatchDeleteIndivRecord").Infof(" the idStr is:%+v,", rPIds)
	if len(rPIds.RoomPlayerIds) <= 0 {
		c.JSON(http.StatusOK, gin.H{"code": utils.ReqParamErr, "msg": "参数不能为空"})
		return
	}
	roomPlayerIds := utils.StrArray2String(rPIds.RoomPlayerIds)
	res := s.mysql.BatchDeleteIndivRecord(roomPlayerIds)
	if !res {
		c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": "", "data": utils.EncryptDataByAes(res)})
		return
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(res)})
}

func (s *Srv) HttpGet(url string, data []byte) ([]byte, error) {
	req, err := http.NewRequest("GET", url, bytes.NewBuffer(data))
	if err != nil {
		return nil, err
	}
	client := http.Client{
		Timeout: time.Duration(2 * time.Second),
	}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	} else if resp.StatusCode != http.StatusOK {
		errMsg := fmt.Sprintf("http request failure. url = %s the respcode is:%d", url, resp.StatusCode)
		return nil, errors.New(errMsg)
	}
	defer resp.Body.Close()
	msg, _ := ioutil.ReadAll(resp.Body)
	return msg, nil
}

// 查询周期会议规则
func (s *Srv) GetCycleRuleByGroupId(c *gin.Context) {
	groupId := c.Query("groupId")
	cycleRule := s.mysql.GetCycleRuleByGroupId(groupId)
	if cycleRule == nil {
		c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": ""})
		return
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(cycleRule)})
}

// 进房校验
func (s *Srv) IncomingCheck(c *gin.Context) {
	roomId := c.Query("roomId")
	meetingPassword := c.Query("meetingPassword")
	log.WithField("Func", "IncomingCheck").Infof(" the roomId is:%s,the meetingPassword is:%s", roomId, meetingPassword)

	confe := s.mysql.GetRoomState(roomId)

	if confe == nil {
		log.WithField("Func", "IncomingCheck").Errorf("incomingcheck the conf is nil %s", roomId)
		c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": ""})
		return
	}
	if confe.Type == 1 {
		confe.State = 1
	}
	if confe.ConfeId == 0 {
		confe.State = 3
		log.WithField("Func", "IncomingCheck").Errorf("incomingcheck the conf id is zero conf error %s", roomId)
		c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(confe)})
		return
	}
	userIdStr := c.Query("userId")
	userId, _ := strconv.ParseInt(userIdStr, 10, 64)
	if confe.Allow == 0 {
		//主持人放行，其他人需要判断主持人是否已进房
		if confe.Creator != userId {
			roomPlayerId := s.mysql.SelectRoomPlayer(roomId, confe.Creator)
			if roomPlayerId == -1 {
				c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": ""})
				return
			}
			if roomPlayerId != 0 {
				confe.Allow = 1
			}
		} else {
			confe.Allow = 1
		}
	}
	if confe.SetPassword == 1 {
		//会议创建者不需要输入密码
		if confe.Creator != userId {
			if meetingPassword == "" {
				c.JSON(http.StatusOK, gin.H{"code": -1, "msg": "请输入密码"})
				return
			}
			if confe.MeetingPassword != meetingPassword {
				c.JSON(http.StatusOK, gin.H{"code": utils.PasswordError, "msg": "密码错误"})
				return
			}
		}
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(confe)})
}

// 进房
func (s *Srv) EnterRoom(c *gin.Context) {
	var param utils.EnterRoomReq
	if err := c.ShouldBind(&param); err != nil {
		log.WithField("func", "EnterRoom").Errorf(err.Error())
		c.JSON(http.StatusOK, gin.H{"code": utils.ReqParamErr, "msg": ""})
		return
	}
	log.WithField("Func", "EnterRoom").Debugf(" The param is:%v", param)
	appId := param.AppId
	userId := param.UserId
	roomId := param.RoomId
	err := s.TLSSig.CheckTLSSignature(userId, param.UserSig)
	if err != nil {
		log.WithField("Func", "EnterRoom").Errorf(err.Error())
		c.JSON(http.StatusOK, gin.H{"code": utils.ServiceInternalErr, "msg": ""})
		return
	}
	roomInfo := s.mysql.GetRoomInfoByRoomId(roomId)
	if roomInfo == nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": utils.DBError, "msg": ""})
		return
	}
	if *roomInfo == (utils.RoomInfo{}) {
		roomRes, err := s.createRoomInfo(appId, userId, roomId)
		if err != nil {
			log.WithField("Func", "EnterRoom").Errorf(" room is not exist Create it :%s,%s err is:%v", roomId, userId, err)
			c.JSON(http.StatusOK, gin.H{"code": utils.ServiceInternalErr, "msg": "", "data": nil})
			return
		}
		c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(*roomRes)})
		return
	}
	DetailUrl := conf.ConfigFile.MediaHost + "/v5/conference/detail"
	detail := utils.DetailReq{
		ConferenceId: roomInfo.ConfId,
		Password:     roomInfo.Password,
	}
	reqData, _ := json.Marshal(detail)
	msg, err := utils.HttpRequest(DetailUrl, "", reqData)
	if err != nil {
		log.WithField("Func", "EnterRoom").Errorf(err.Error())
		c.JSON(http.StatusOK, gin.H{"code": utils.RemoteReqFail, "msg": ""})
		return
	}
	RspMsg := make(map[string]interface{})
	err = json.Unmarshal(msg, &RspMsg)
	if err != nil {
		log.WithField("Func", "EnterRoom").Errorf("convert to RspMsg fail %v", err.Error())
		c.JSON(http.StatusOK, gin.H{"code": utils.ServiceInternalErr, "msg": ""})
		return
	}
	inValid := RspMsg["inValid"]
	if value, ok := inValid.(bool); ok && value {
		s.mysql.EditConferState(3, roomInfo.Id)
		roomRes, err := s.createRoomInfo(appId, userId, roomId)
		if err != nil {
			c.JSON(http.StatusOK, gin.H{"code": utils.ServiceInternalErr, "msg": ""})
			return
		}
		c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(*roomRes)})
		return
	}

	TktUrl := conf.ConfigFile.MediaHost + "/v5/conference/multieople/reqtkt"
	tktReq := utils.TktReq{
		ConfrId:  roomInfo.ConfId,
		Password: roomInfo.Password,
		MemName:  userId,
	}
	reqData, _ = json.Marshal(tktReq)
	msg, _ = utils.HttpRequest(TktUrl, "", reqData)
	tktRsp := make(map[string]string)
	err = json.Unmarshal(msg, &tktRsp)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"code": utils.ServiceInternalErr, "msg": ""})
		return
	}
	roomRes := utils.EnterRoomRes{
		ConfId:   roomInfo.ConfId,
		RoomId:   roomId,
		Password: roomInfo.Password,
		Ticket:   tktRsp["tkt"],
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "entry successful", "data": utils.EncryptDataByAes(roomRes)})
}

// 创建会议
func (s *Srv) createRoomInfo(appId int64, userId, roomId string) (*utils.EnterRoomRes, error) {
	uuid := uuid.NewV4().String()
	callbackHost := conf.ConfigFile.CallbackHost
	url := conf.ConfigFile.MediaHost + "/v5/kefu/conference/multieople/create"
	var users []string
	users = append(users, userId)
	users = append(users, uuid[0:16])
	req := utils.CreateConferenceReq{
		MediaType:         0,
		EvtCallbackUrl:    fmt.Sprintf("%s/management/apps/%d/meetings/%s/evt", callbackHost, appId, uuid),
		CallbackTimeoutMs: 180000,
		RtcMergedFlag:     true,
		Users:             users,
		Timestamp:         time.Now().UnixMilli(),
	}
	req.Sign = utils.GetSign("", req.CallbackUrl, "", "", users, req.Timestamp)
	reqData, _ := json.Marshal(&req)
	msg, err := utils.HttpRequest(url, "", reqData)
	rsp := utils.CreateConferenceRes{}
	log.WithField("Func", "createRoomInfo").Errorf(" http req response:%s e rr is:%v", string(msg), err)
	err = json.Unmarshal(msg, &rsp)
	if err != nil {
		return nil, err
	}
	index := -1
	for a, value := range rsp.Tickets {
		var t utils.Ticket
		err := json.Unmarshal([]byte(value), &t)
		if err != nil {
			return nil, err
		}
		if t.MemName == userId {
			index = a
			break
		}
	}
	if index < 0 {
		return nil, errors.New("ticket is nil")
	}
	confer := utils.RoomInfoCreate{
		AppId:     appId,
		Uuid:      uuid,
		RoomId:    roomId,
		ConfrId:   rsp.ConfrId,
		RoomType:  "Vedio",
		ConfrType: "Imme",
		Creator:   userId,
		Password:  rsp.Password,
		State:     0,
	}
	s.mysql.CreateRoomInfo(&confer)
	roomRes := utils.EnterRoomRes{
		ConfId:   rsp.ConfrId,
		RoomId:   roomId,
		Password: rsp.Password,
		Ticket:   rsp.Tickets[index],
	}
	return &roomRes, nil
}

// 视频会议历史列表查询
// 要支持搜索：会议名称、会议号、发起人
func (s *Srv) GetHisConfList(c *gin.Context) {
	userIdStr := c.Request.Header.Get("userId")
	queryParams := c.Query("queryParams")
	if userIdStr == "" {
		c.JSON(http.StatusOK, gin.H{"code": utils.ReqParamErr, "msg": "参数不能为空"})
		return
	}
	log.WithField("Func", "GetHisConfList").Infof(" the userIdStr is:%s,the queryParams is:%s", userIdStr, queryParams)
	userId, _ := strconv.ParseInt(userIdStr, 10, 64)
	confSlic := s.mysql.GetHistoryConfListByParam(userId, queryParams)
	if confSlic == nil {
		c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": ""})
		return
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(confSlic)})
}

// 视频会议历史详情查询
// 要支持搜索：会议名称、会议号、发起人
func (s *Srv) GetHisConfDetail(c *gin.Context) {
	confeId := c.Query("confeId")
	if confeId == "" {
		c.JSON(http.StatusBadRequest, gin.H{"code": utils.ReqParamErr, "msg": "参数错误"})
		return
	}
	id, _ := strconv.ParseInt(confeId, 10, 64)
	confer := s.mysql.GetHisConferDetailById(id)
	if confer == nil {
		c.JSON(http.StatusBadRequest, gin.H{"code": utils.DBError, "msg": ""})
		return
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(confer)})
}

// 删除会议视频记录
func (s *Srv) DeleteConferenceRecord(c *gin.Context) {
	idStr := c.Query("confeId")
	recordId := c.Query("recordId")
	userId := c.GetHeader("userId")
	log.WithField("Func", "DeleteConferenceRecord").Infof(" the idStr is:%s,the recordId is:%s,the userId is:%s", idStr, recordId, userId)
	if idStr == "" {
		c.JSON(http.StatusOK, gin.H{"code": utils.ReqParamErr, "msg": "会议号不能为空"})
		return
	}
	id, _ := strconv.ParseInt(idStr, 10, 64)
	res := s.mysql.DeleteConferenceRecord(id, userId, recordId)
	if !res {
		c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": "", "data": utils.EncryptDataByAes(res)})
		return
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(res)})
}

// 修改会议录制记录标识
func (s *Srv) EditConfeRecordFlag(c *gin.Context) {
	idStr := c.Query("confeId")
	recordFlag := c.Query("recordFlag")
	log.WithField("Func", "EditConfeRecordFlag").Infof(" the idStr is:%s,the recordflag is:%s", idStr, recordFlag)
	if idStr == "" {
		c.JSON(http.StatusOK, gin.H{"code": utils.ReqParamErr, "msg": "会议号不能为空"})
		return
	}
	if recordFlag == "" {
		c.JSON(http.StatusOK, gin.H{"code": utils.ReqParamErr, "msg": "修改录制标识不能为空"})
		return
	}
	id, _ := strconv.ParseInt(idStr, 10, 64)
	recordFlagConv, _ := strconv.Atoi(recordFlag)
	res := s.mysql.EditConfeRecordFlag(id, recordFlagConv)
	if !res {
		c.JSON(http.StatusOK, gin.H{"code": utils.DBError, "msg": "", "data": utils.EncryptDataByAes(res)})
		return
	}
	c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(res)})
}

func (s *Srv) Contorlmsg(c *gin.Context) {
	var controlmsg utils.FSContorlMsg
	if err := c.ShouldBindBodyWith(&controlmsg, binding.JSON); err != nil {
		log.WithField("func", "Contorlmsg").Errorf("fs contorlmsg error the err is:%s", err.Error())
		c.JSON(http.StatusBadRequest, gin.H{"code": utils.ReqParamErr, "msg": ""})
		return
	}
	control := controlmsg.Data
	log.WithField("func", "Contorlmsg").Errorf("the fs control msg is:%s the conferid is:%s the telphone is:%d",
		control, controlmsg.ConferId, controlmsg.Telphone)
	err := s.fsCli.SendMsgToFs(control)

	if err != nil && err.Error() == "EOF" {
		err = s.fsCli.SendMsgToFs(control)
	}
	if err != nil {
		log.WithField("func", "Contorlmsg").Errorf("send msg to fs error the errmsg is:%s,msg is:%v", err.Error(), control)
		c.JSON(http.StatusOK, gin.H{"code": utils.FSControlErr, "msg": err.Error(), "data": ""})
	} else {
		c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": ""})
	}
}
func (s *Srv) FSContorl(c *gin.Context) {
	var controlmsg utils.FSSingleContorlMsg
	if err := c.ShouldBindBodyWith(&controlmsg, binding.JSON); err != nil {
		log.WithField("func", "Contorlmsg").Errorf("fs contorlmsg error the err is:%s", err.Error())
		c.JSON(http.StatusBadRequest, gin.H{"code": utils.ReqParamErr, "msg": ""})
		return
	}
	control := controlmsg.Data
	log.WithField("func", "Contorlmsg").Errorf("the fs control msg is:%s the conferid is:%s the telphone is:%d",
		control, controlmsg.ConferId, controlmsg.Telphone)

	ev, err := s.fsCli.SingelSendMsgToFs(control)

	if err != nil && err.Error() == "EOF" {
		ev, err = s.fsCli.SingelSendMsgToFs(control)
	}
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"code": utils.FSControlErr, "msg": err.Error(), "data": ""})
	} else {
		c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": utils.EncryptDataByAes(ev)})
	}
}
func (s *Srv) StartRecord(c *gin.Context) {
	roomid := c.Query("roomId")
	if roomid == "" {
		c.JSON(http.StatusOK, gin.H{"code": utils.ReqParamErr, "msg": "房间号不能为空"})
		return
	}
	recordfile := utils.FormatAsString(time.Now(), utils.STRING_FORMAT_TIME_YYYYMMDDHHMMSS)
	path := conf.ConfigFile.RecordPath + "/" + roomid + "-" + recordfile + ".mp4"
	control := fmt.Sprintf("api conference %s recording start %s", roomid, path)

	log.WithField("func", "StartRecord").Infof("fs StartRecord the cmd is:%s", control)

	_, err := s.fsCli.SingelSendMsgToFs(control)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"code": utils.FSControlErr, "msg": err.Error(), "data": ""})
	} else {
		c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": "", "data": ""})
	}
}
func (s *Srv) SyncApiCommand(c *gin.Context) {
	var controlmsg utils.SyncApiCommandMsq
	if err := c.ShouldBindBodyWith(&controlmsg, binding.JSON); err != nil {
		log.WithField("func", "SyncApiCommand").Errorf("fs contorlmsg error the err is:%s", err.Error())
		c.JSON(http.StatusBadRequest, gin.H{"code": utils.ReqParamErr, "msg": ""})
		return
	}
	control := fmt.Sprintf("api %s %s", controlmsg.Command, controlmsg.Arg)
	log.WithField("func", "SyncApiCommand").Infof("fs the cmd is:%s", control)
	ev, err := s.fsCli.SingelSendMsgToFs(control)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{"code": utils.FSControlErr, "msg": err.Error(), "data": ""})
	} else {
		c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": ev})
	}
}

func (s *Srv) SendMsg(c *gin.Context) {
	var sendmsg utils.SnedMsg
	if err := c.ShouldBindBodyWith(&sendmsg, binding.JSON); err != nil {
		log.WithField("func", "SendMsg").Errorf("send phone msg error the err is:%s", err.Error())
		c.JSON(http.StatusBadRequest, gin.H{"code": utils.ReqParamErr, "msg": ""})
		return
	}
	if sendmsg.Telphone == "" {
		c.JSON(http.StatusOK, gin.H{"code": utils.ReqParamErr, "msg": "手机号为空"})
		return
	}
	if sendmsg.Url == "" {
		c.JSON(http.StatusOK, gin.H{"code": utils.ReqParamErr, "msg": "url为空"})
		return
	}
	msg := smscode.SendCode("", sendmsg.Telphone, "34081", sendmsg.Url)
	if msg != "" {
		c.JSON(http.StatusOK, gin.H{"code": utils.FSControlErr, "msg": msg, "data": ""})
	} else {
		c.JSON(http.StatusOK, gin.H{"code": utils.Success, "msg": ""})
	}
}
